﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Multiprocessing.Core.Mathematics.Graphs
{
    public sealed class GraphNode<TNodeKey, TNodeValue, TRibValue>
    {
        #region Fields

        private readonly IList<DirectionalRib<TNodeKey, TNodeValue, TRibValue>> _ribs;

        #endregion

        #region Properties

        public TNodeKey Key { get; private set; }

        public IEnumerable<DirectionalRib<TNodeKey, TNodeValue, TRibValue>> Ribs
        {
            get { return _ribs; }
        }

        public TNodeValue Value { get; set; }

        #endregion

        #region Constructors

        public GraphNode(TNodeKey key, TNodeValue value)
        {
            _ribs = new List<DirectionalRib<TNodeKey, TNodeValue, TRibValue>>();
            this.Key = key;
            this.Value = value;
        }

        public GraphNode(TNodeKey key)
            : this(key, default (TNodeValue))
        {
        }

        #endregion

        #region Methods

        public void AddRibTo(GraphNode<TNodeKey, TNodeValue, TRibValue> @to, TRibValue weight)
        {
            var rib = new DirectionalRib<TNodeKey, TNodeValue, TRibValue>(weight, this, @to);
            _ribs.Add(rib);
        }

        public bool RemoveRibTo(GraphNode<TNodeKey, TNodeValue, TRibValue> node)
        {
            if (ReferenceEquals(node, null))
            {
                throw new ArgumentNullException("to");
            }
            if (this.HasRibTo(node))
            {
                var rib = this.GetRibTo(node);
                _ribs.Remove(rib);
                return true;
            }
            return false;
        }

        public bool HasRibTo(GraphNode<TNodeKey, TNodeValue, TRibValue> node)
        {
            if (ReferenceEquals(node, null))
            {
                throw new ArgumentNullException("node");
            }
            return !ReferenceEquals(_ribs.SingleOrDefault(rib => rib.To == node), null);
        }

        public DirectionalRib<TNodeKey, TNodeValue, TRibValue> GetRibTo(GraphNode<TNodeKey, TNodeValue, TRibValue> node)
        {
            if (ReferenceEquals(node, null))
            {
                throw new ArgumentNullException("node");
            }
            return _ribs.Single(rib => rib.To == node);
        }

        #endregion
    }
}
